/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * RSTechniqueElement.cpp
 *
 *  Created on: 2010/03/08
 *      Author: Alexandre Pires ( c.alexandre.pires@gmail.com )
 */

#include "RSTechniqueElement.h"
#include "RSValueElement.h"

namespace Realsphere {

    RSTechniqueElement::RSTechniqueElement ( const QString& rTag, const QString& rScopeId ) :
            RSElement ( rTag )
    {
        mScopeId = rScopeId;
    }

    RSTechniqueElement::~RSTechniqueElement ()
    {
        mValueElements.clear();
    }

    QString RSTechniqueElement::ScopeId () const {
        return mScopeId;
    }

    RSValueElement* RSTechniqueElement::GetValueElement ( const QString& rScopeId ) {

        RSValueElementsIterator iterator = RSValueElementsIterator(mValueElements);

        while ( iterator.hasNext() ) {

            RSValueElement* value_element = iterator.next();

            if ( value_element->ScopeId() == rScopeId )
                return value_element;
        }

        return NULL;
    }

    RSValueElement* RSTechniqueElement::GetValueElement ( unsigned int rIndex ) {
        return mValueElements[rIndex];
    }

    int RSTechniqueElement::IndexOf ( RSValueElement* rValueElement ) {
        return mValueElements.indexOf ( rValueElement );
    }

    unsigned int RSTechniqueElement::ValueElementsSize () {
        return mValueElements.size();
    }

    RSValueElements RSTechniqueElement::ValueElements() const {
        return mValueElements;
    }

    RSValueElementsIterator RSTechniqueElement::ValueElementsIterator() const {
        return RSValueElementsIterator ( mValueElements );
    }

    bool RSTechniqueElement::IsRootElement() const {
        return false;
    }

    void RSTechniqueElement::SetScopeId ( const QString& rScopeId, bool rEmit ) {
        mScopeId = rScopeId;

        if ( rEmit )
            emit ScopeIdChanged ( mScopeId );
    }

    RSError RSTechniqueElement::AddValueElement ( RSValueElement* rValueElement ) {
        RSError error = AddChildElement ( rValueElement );
        return error;
    }

    RSError RSTechniqueElement::RemoveValueElement ( RSValueElement* rValueElement ) {
        RSError error = RemoveChildElement ( rValueElement );
        return error;
    }

    RSError RSTechniqueElement::RemoveValueElement ( unsigned int rIndex ) {
        RSValueElement* value_element = mValueElements[rIndex];
        RSError error = RemoveValueElement ( value_element );
        return error;
    }

    RSError RSTechniqueElement::RemoveValueElement ( const QString& rScopeId ) {
        RSValueElement* value_element = GetValueElement( rScopeId );
        RSError error = RemoveValueElement ( value_element );
        return error;
    }

    RSError RSTechniqueElement::BeforeAddChildElement ( RSElement* rChild ) {

        RSError error = RSElement::BeforeAddChildElement ( rChild );

        if ( error == RS_INVALID_ELEMENT ) {

            if ( rChild->InstanceOf( RS_VALUE_ELEMENT_CLASS ) ) {

                RSValueElement* value_element = RSValueElementCast( rChild );
                error = BeforeAddValueElementValidation ( value_element );
            }
        }

        return error;
    }

    RSError RSTechniqueElement::BeforeRemoveChildElement ( RSElement* rChild ) {

        RSError error = RSElement::BeforeRemoveChildElement ( rChild );

        if ( error == RS_INVALID_ELEMENT ) {

            if ( rChild->InstanceOf( RS_VALUE_ELEMENT_CLASS ) ) {

                RSValueElement* value_element = RSValueElementCast( rChild );
                error = BeforeRemoveValueElementValidation ( value_element );
            }
        }

        return error;
    }

    bool RSTechniqueElement::AfterAddChildElement ( RSElement* rChild ) {

        bool handled = RSElement::AfterAddChildElement ( rChild );

        if ( !handled ) {

            if ( rChild->InstanceOf ( RS_VALUE_ELEMENT_CLASS ) ) {

                RSValueElement* value_element = RSValueElementCast( rChild );
                mValueElements.append ( value_element );
                connect ( value_element, SIGNAL ( ValueChanged() ), this, SIGNAL ( TechniqueElementChanged() ) );
                AfterAddValueElementValidation ( value_element );
                handled = true;

                emit ValueElementAdded ( value_element );
            }
        }

        return handled;
    }

    bool RSTechniqueElement::AfterRemoveChildElement ( RSElement* rChild ) {

        bool handled = RSElement::AfterRemoveChildElement ( rChild );

        if ( !handled ) {

            if ( rChild->InstanceOf ( RS_VALUE_ELEMENT_CLASS ) ) {

                RSValueElement* value_element = RSValueElementCast( rChild );
                int index = mValueElements.indexOf ( value_element );
                mValueElements.removeAt ( index );
                disconnect ( value_element, SIGNAL ( ValueChanged() ), this, SIGNAL ( TechniqueElementChanged() ) );
                AfterRemoveValueElementValidation ( value_element );
                handled = true;

                emit ValueElementRemoved ( value_element );
            }
        }

        return handled;
    }

    RSError RSTechniqueElement::BeforeAddValueElementValidation ( RSValueElement* rValueElement )
    {
        RSError error = RS_INVALID_VALUE;

        /*RSValueElement* scoped_value = GetValueElement ( rValueElement->ScopeId() );

        if ( scoped_value != NULL )
            error = RS_SID_ALREADY_TAKEN;*/

        return error;
    }


    RSError RSTechniqueElement::BeforeRemoveValueElementValidation ( RSValueElement* rValueElement )
    {
        return RS_INVALID_VALUE;
    }

    bool RSTechniqueElement::AfterAddValueElementValidation ( RSValueElement* rValueElement )
    {
        return false;
    }

    bool RSTechniqueElement::AfterRemoveValueElementValidation ( RSValueElement* rValueElement )
    {
        return false;
    }
}
